package com.jacky.ws.config;

import com.corundumstudio.socketio.AckMode;
import com.corundumstudio.socketio.AuthorizationResult;
import com.corundumstudio.socketio.SocketConfig;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.store.RedissonStoreFactory;
import com.corundumstudio.socketio.store.pubsub.PubSubStore;
import com.jacky.ws.handler.SocketIOEventHandler;
import com.jacky.ws.properties.WebSocketProperties;
import com.jacky.ws.redis.CustomRedissonStoreFactory;
import io.netty.handler.codec.http.HttpHeaders;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SocketIOConfig {

    private final Logger LOG = LoggerFactory.getLogger(SocketIOConfig.class);

    private final RedissonClient redissonClient;
    private final WebSocketProperties wsProperties;
    private final SocketIOEventHandler eventHandler;

    public SocketIOConfig(RedissonClient redissonClient, WebSocketProperties wsProperties,SocketIOEventHandler eventHandler) {
        this.redissonClient = redissonClient;
        this.wsProperties = wsProperties;
        this.eventHandler = eventHandler;
    }

    private RedissonStoreFactory createRedissonStoreFactory() {
        LOG.info("创建 RedissonStoreFactory 结束");
        CustomRedissonStoreFactory factory = new CustomRedissonStoreFactory(redissonClient);
        LOG.info("创建 RedissonStoreFactory 结束");
        return factory;
    }

    @Bean(name = "socketIOServer")
    public SocketIOServer createSocketIOServer() {
        LOG.info("创建 SocketIOServer 开始");
        SocketConfig sConfig = new SocketConfig();
        sConfig.setTcpNoDelay(true);
        sConfig.setTcpKeepAlive(true);
        // 在默认情况下,当调用close关闭socket的使用,close会立即返回
        // 但是,如果send buffer中还有数据,系统会试着先把send buffer中的数据发送出去,然后close才返回
        sConfig.setSoLinger(0);

        com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration();
        config.setHostname(wsProperties.getHost());
        // 设置监听端口
        config.setPort(wsProperties.getSocketPort());
//        config.setBossThreads(1);
//        config.setWorkerThreads(24);
//        config.setAllowCustomRequests(true);

        // 设置http协议升级为ws协议的超时时间
        config.setUpgradeTimeout(wsProperties.getUpgradeTimeout());
        // ping消息间隔时间
        config.setPingInterval(wsProperties.getPingInterval());
        // ping消息超时时间
        config.setPingTimeout(wsProperties.getPingTimeout());
        // 消息存储方式
        config.setStoreFactory(this.createRedissonStoreFactory());
        // 手动确认
        config.setAckMode(AckMode.MANUAL);
        config.setAuthorizationListener(data -> {
            // 从消息头中获取token
            HttpHeaders httpHeaders = data.getHttpHeaders();
            String token = httpHeaders.get("Authorization");
            return new AuthorizationResult(true);
        });

        config.setSocketConfig(sConfig);
        LOG.info("创建 SocketIOServer结束");
        SocketIOServer server = new SocketIOServer(config);
        server.addListeners(eventHandler);
        // 可以添加命名空间,多次调用添加多个
//        server.addNamespace("/socketIo");
        return server;
    }

    @Bean
    public PubSubStore pubSubStore(SocketIOServer server) {
        return server.getConfiguration().getStoreFactory().pubSubStore();
    }

}
